package com.wei.czz.framework.rabbitMQ.listener.dept;

import com.wei.czz.common.constant.EntityConstant;
import com.wei.czz.common.enums.CommonEnum;
import com.wei.czz.common.enums.admin.userRole.RelationModeEnum;
import com.wei.czz.common.enums.rabbitMQ.MqEnum;
import com.wei.czz.common.utils.CacheKeyUtils;
import com.wei.czz.common.utils.CopyUtils;
import com.wei.czz.framework.admin.entity.DeptEntity;
import com.wei.czz.framework.admin.entity.DeptRoleEntity;
import com.wei.czz.framework.admin.entity.DeptUserEntity;
import com.wei.czz.framework.admin.entity.UserRoleEntity;
import com.wei.czz.framework.admin.service.DeptRoleService;
import com.wei.czz.framework.admin.service.DeptService;
import com.wei.czz.framework.admin.service.DeptUserService;
import com.wei.czz.framework.admin.service.UserRoleService;
import com.wei.czz.framework.common.service.TransactionService;
import com.wei.czz.framework.rabbitMQ.message.dept.DeptRoleMessage;
import lombok.AllArgsConstructor;
import org.apache.commons.lang3.StringUtils;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;

import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * Created by IntelliJ IDEA.
 *
 * @author wyw
 * date: 2024-12-16 18:17:24
 * className: DeptRoleQueueListener
 * version: 1.0
 * description:
 */
@Component
@AllArgsConstructor
public class DeptRoleQueueListener {

    private static final Logger log = LoggerFactory.getLogger(DeptRoleQueueListener.class);

    private final DeptService deptService;

    private final DeptUserService deptUserService;

    private final DeptRoleService deptRoleService;

    private final UserRoleService userRoleService;

    private final TransactionService transactionService;

    private final RedissonClient redissonClient;

    /**
     * 部门关联角色变化消息监听方法
     */
    @RabbitListener(queues = { MqEnum.Queue.DEPT_ROLE })
    public void deptRoleMessage(DeptRoleMessage deptRoleMessage) {
        log.info("开始部门关联角色变化消息处理。{}", deptRoleMessage);

        String lockKey = CacheKeyUtils.getMqMessageLockKey(EntityConstant.DEPT_ROLE, MqEnum.Queue.DEPT_ROLE);

        RLock lock = redissonClient.getLock(lockKey);
        // 加锁一分钟
        lock.lock(1, TimeUnit.MINUTES);

        try {
            // 处理方法
            this.handler(deptRoleMessage);

        } finally {
            if (lock.isLocked() && lock.isHeldByCurrentThread()) {
                lock.unlock();
            }
        }

        log.info("部门关联角色变化消息处理结束");
    }

    /**
     * 消息处理方法
     * @param deptRoleMessage 消息对象
     */
    public void handler(DeptRoleMessage deptRoleMessage) {
        Date date = new Date();

        // 部门主键
        Long deptId = deptRoleMessage.getDeptId();
        List<Long> deptIdList = Collections.singletonList(deptId);
        // 角色主键列表
        List<Long> roleIdList = deptRoleMessage.getRoleIdList();

        /*
            获取部门与角色关联列表
         */
        List<DeptRoleEntity> deptRoleList = deptRoleService.findList(deptIdList, roleIdList);
        /*
            1、如果查询结果为空，则说明是删除操作
            2、如果结果列表里的所有元素状态都是停用，则说明是删除操作
         */
        boolean isDelete = CollectionUtils.isEmpty(deptRoleList);

        /*
            获取部门用户
         */
        List<DeptUserEntity> deptUserList = deptUserService.findList(deptIdList, null);

        /*
            获取子、子孙部门主键
         */
        deptIdList = deptService.getChildrenIdList(deptId);

        /*
            获取子、子孙部门关联用户
         */
        List<DeptUserEntity> childrenDeptUserList = deptUserService.findList(deptIdList, null);

        // 收集用户主键
        List<Long> userIdList = CopyUtils.mapList(deptUserList, DeptUserEntity::getUserId);
        userIdList.addAll(CopyUtils.mapList(childrenDeptUserList, DeptUserEntity::getUserId));

        /*
            获取用户关联角色（通过部门关联角色）
         */
        List<UserRoleEntity> userRoleList = userRoleService.findUserRoleList(userIdList, roleIdList,
                Collections.singletonList(RelationModeEnum.DEPT_ROLE.getValue()));
        // 按用户分组
        Map<Long, List<UserRoleEntity>> userRoleMap = userRoleList.stream()
                .collect(Collectors.groupingBy(UserRoleEntity::getUserId));

        /*
            获取用户关联部门
         */
        List<DeptUserEntity> userDeptList = deptUserService.findList(null, userIdList);
        Set<Long> deptIdSet = CopyUtils.mapSet(userDeptList, DeptUserEntity::getDeptId);
        deptIdList = new ArrayList<>(deptIdSet);

        /*
            获取部门列表
         */
        List<DeptEntity> deptList = deptService.getList(deptIdList);

        Map<Long, List<Long>> parentDeptMap = new HashMap<>();
        for (DeptEntity dept : deptList) {
            /*
                获取父级部门主键列表
             */
            List<Long> parentIdList = deptService.findParentIdList(dept);
            // 从父级部门主键列表中删除正在操作的部门主键
            parentIdList.remove(deptId);
            // 合并
            deptIdList.addAll(parentIdList);
            // 部门与父级部门映射
            parentDeptMap.put(dept.getId(), parentIdList);
        }

        /*
            获取部门与角色关联列表
         */
        List<DeptRoleEntity> _deptRoleList = deptRoleService.findList(deptIdList, roleIdList);
        // 按部门分组
        Map<Long, List<DeptRoleEntity>> deptRoleMap = _deptRoleList.stream()
                .collect(Collectors.groupingBy(DeptRoleEntity::getDeptId));

        Map<Long, Set<Long>> userOtherRoleMap = new HashMap<>();
        for (DeptUserEntity deptUser : userDeptList) {
            Long _deptId = deptUser.getDeptId();
            Long userId = deptUser.getUserId();

            // 构造用户通过部门关联的角色（排除正在操作的部门）
            Set<Long> roleIdSet = userOtherRoleMap.computeIfAbsent(userId, k -> new HashSet<>());

            // 获取正在遍历的部门，其对应的所有父级部门主键列表
            deptIdList = parentDeptMap.getOrDefault(_deptId, new ArrayList<>());
            // 将正在遍历的部门主键加入列表中
            deptIdList.add(_deptId);
            for (Long __deptId : deptIdList) {
                _deptRoleList = deptRoleMap.getOrDefault(__deptId, Collections.emptyList());
                for (DeptRoleEntity deptRole : _deptRoleList) {
                    roleIdSet.add(deptRole.getRoleId());
                }
            }
        }

        List<UserRoleEntity> saveList = new ArrayList<>();
        List<UserRoleEntity> updateList = new ArrayList<>();

        if (isDelete) {
            for (Long roleId : roleIdList) {

                for (DeptUserEntity deptUser : deptUserList) {
                    // 获取用户关联角色列表
                    userRoleList = userRoleMap.getOrDefault(deptUser.getUserId(), Collections.emptyList());
                    // 判断用户是否已关联该角色
                    userRoleList = userRoleList.stream()
                            .filter(userRole -> userRole.getRoleId().equals(roleId))
                            .collect(Collectors.toList());
                    boolean bool = userRoleList.isEmpty();
                    if (!bool) {
                        // 获取用户通过部门关联角色主键集合（排除正在操作的部门主键）
                        Set<Long> roleIdSet = userOtherRoleMap.getOrDefault(deptUser.getUserId(), Collections.emptySet());
                        // 获取用户是否通过部门关联正在遍历的角色
                        bool = roleIdSet.contains(roleId);
                    }
                    log.info("用户取消关联角色。userId={} roleId={} bool={}", deptUser.getUserId(), roleId, bool);
                    if (!bool) {
                        for (UserRoleEntity userRole : userRoleList) {
                            UserRoleEntity updateUserRole = new UserRoleEntity();
                            updateUserRole.setId(userRole.getId())
                                    .setDeleteStatus(CommonEnum.ONE.getValue())
                                    .setUpdateTime(date)
                                    .setUpdateUser(StringUtils.EMPTY)
                                    .setUpdateUserId(CommonEnum.ZERO.getLongValue());
                            updateList.add(updateUserRole);
                        }
                    }
                }
                for (DeptUserEntity deptUser : childrenDeptUserList) {
                    // 获取用户关联角色列表
                    userRoleList = userRoleMap.getOrDefault(deptUser.getUserId(), Collections.emptyList());
                    // 判断用户是否已关联该角色
                    userRoleList = userRoleList.stream()
                            .filter(userRole -> userRole.getRoleId().equals(roleId))
                            .collect(Collectors.toList());
                    boolean bool = userRoleList.isEmpty();
                    if (!bool) {
                        // 获取用户通过部门关联角色主键集合（排除正在操作的部门主键）
                        Set<Long> roleIdSet = userOtherRoleMap.getOrDefault(deptUser.getUserId(), Collections.emptySet());
                        // 获取用户是否通过部门关联正在遍历的角色
                        bool = roleIdSet.contains(roleId);
                    }
                    log.info("用户取消关联角色。deptId={} userId={} roleId={} bool={}", deptUser.getDeptId(),
                            deptUser.getUserId(), roleId, bool);
                    if (!bool) {
                        for (UserRoleEntity userRole : userRoleList) {
                            UserRoleEntity updateUserRole = new UserRoleEntity();
                            updateUserRole.setId(userRole.getId())
                                    .setDeleteStatus(CommonEnum.ONE.getValue())
                                    .setUpdateTime(date)
                                    .setUpdateUser(StringUtils.EMPTY)
                                    .setUpdateUserId(CommonEnum.ZERO.getLongValue());
                            updateList.add(updateUserRole);
                        }
                    }
                }

            }
        }

        for (DeptRoleEntity deptRole : deptRoleList) {

            for (DeptUserEntity deptUser : deptUserList) {
                // 获取用户关联角色列表
                userRoleList = userRoleMap.getOrDefault(deptUser.getUserId(), Collections.emptyList());
                log.info("用户关联角色数量。userId={} list.size={}", deptUser.getUserId(), userRoleList.size());
                // 判断用户是否可以关联该角色
                if (CommonEnum.ZERO.getValue().equals(deptRole.getStatus()) && this.checkDirectUser(deptRole, deptUser)) {
                    /*
                        可以
                     */
                    // 判断用户是否已关联该角色
                    boolean bool = userRoleList.stream()
                            .noneMatch(userRole -> userRole.getRoleId().equals(deptRole.getRoleId()));
                    log.info("用户新关联角色。userId={} roleId={} bool={}", deptUser.getUserId(), deptRole.getRoleId(), bool);
                    if (bool) {
                        UserRoleEntity userRole = new UserRoleEntity();
                        userRole.setUserId(deptUser.getUserId())
                                .setRoleId(deptRole.getRoleId())
                                .setRelationMode(RelationModeEnum.DEPT_ROLE.getValue())
                                .setDeleteStatus(CommonEnum.ZERO.getValue())
                                .setUpdateTime(date)
                                .setUpdateUser(StringUtils.EMPTY)
                                .setUpdateUserId(CommonEnum.ZERO.getLongValue())
                                .setCreateTime(date)
                                .setCreateUser(StringUtils.EMPTY)
                                .setCreateUserId(CommonEnum.ZERO.getLongValue());
                        saveList.add(userRole);
                    }

                } else {
                    /*
                        不可以
                     */
                    // 判断用户是否已关联该角色
                    userRoleList = userRoleList.stream()
                            .filter(userRole -> userRole.getRoleId().equals(deptRole.getRoleId()))
                            .collect(Collectors.toList());
                    boolean bool = userRoleList.isEmpty();
                    if (!bool) {
                        // 获取用户通过部门关联角色主键集合（排除正在操作的部门主键）
                        Set<Long> roleIdSet = userOtherRoleMap.getOrDefault(deptUser.getUserId(), Collections.emptySet());
                        // 获取用户是否通过部门关联正在遍历的角色
                        bool = roleIdSet.contains(deptRole.getRoleId());
                    }
                    log.info("用户取消关联角色。userId={} roleId={} bool={}", deptUser.getUserId(), deptRole.getRoleId(),
                            bool);
                    if (!bool) {
                        for (UserRoleEntity userRole : userRoleList) {
                            UserRoleEntity updateUserRole = new UserRoleEntity();
                            updateUserRole.setId(userRole.getId())
                                    .setDeleteStatus(CommonEnum.ONE.getValue())
                                    .setUpdateTime(date)
                                    .setUpdateUser(StringUtils.EMPTY)
                                    .setUpdateUserId(CommonEnum.ZERO.getLongValue());
                            updateList.add(updateUserRole);
                        }
                    }
                }
            }

            for (DeptUserEntity deptUser : childrenDeptUserList) {
                // 获取用户关联角色列表
                userRoleList = userRoleMap.getOrDefault(deptUser.getUserId(), Collections.emptyList());
                log.info("用户关联角色数量。deptId={} userId={} list.size={}", deptUser.getDeptId(), deptUser.getUserId(),
                        userRoleList.size());
                // 判断用户是否可以关联该角色
                if (CommonEnum.ZERO.getValue().equals(deptRole.getStatus()) && this.checkChildrenUser(deptRole, deptUser)) {
                    /*
                        可以
                     */
                    // 判断用户是否已关联该角色
                    boolean bool = userRoleList.stream()
                            .noneMatch(userRole -> userRole.getRoleId().equals(deptRole.getRoleId()));
                    log.info("用户新关联角色。deptId={} userId={} roleId={} bool={}", deptUser.getDeptId(),
                            deptUser.getUserId(), deptRole.getRoleId(), bool);
                    if (bool) {
                        UserRoleEntity userRole = new UserRoleEntity();
                        userRole.setUserId(deptUser.getUserId())
                                .setRoleId(deptRole.getRoleId())
                                .setRelationMode(RelationModeEnum.DEPT_ROLE.getValue())
                                .setDeleteStatus(CommonEnum.ZERO.getValue())
                                .setUpdateTime(date)
                                .setUpdateUser(StringUtils.EMPTY)
                                .setUpdateUserId(CommonEnum.ZERO.getLongValue())
                                .setCreateTime(date)
                                .setCreateUser(StringUtils.EMPTY)
                                .setCreateUserId(CommonEnum.ZERO.getLongValue());
                        saveList.add(userRole);
                    }
                } else {
                    /*
                        不可以
                     */
                    // 判断用户是否已关联该角色
                    userRoleList = userRoleList.stream()
                            .filter(userRole -> userRole.getRoleId().equals(deptRole.getRoleId()))
                            .collect(Collectors.toList());
                    boolean bool = userRoleList.isEmpty();
                    if (!bool) {
                        // 获取用户通过部门关联角色主键集合（排除正在操作的部门主键）
                        Set<Long> roleIdSet = userOtherRoleMap.getOrDefault(deptUser.getUserId(), Collections.emptySet());
                        // 获取用户是否通过部门关联正在遍历的角色
                        bool = roleIdSet.contains(deptRole.getRoleId());
                    }
                    log.info("用户取消关联角色。deptId={} userId={} roleId={} bool={}", deptUser.getDeptId(),
                            deptUser.getUserId(), deptRole.getRoleId(), bool);
                    if (!bool) {
                        for (UserRoleEntity userRole : userRoleList) {
                            UserRoleEntity updateUserRole = new UserRoleEntity();
                            updateUserRole.setId(userRole.getId())
                                    .setDeleteStatus(CommonEnum.ONE.getValue())
                                    .setUpdateTime(date)
                                    .setUpdateUser(StringUtils.EMPTY)
                                    .setUpdateUserId(CommonEnum.ZERO.getLongValue());
                            updateList.add(updateUserRole);
                        }
                    }
                }
            }

        }

        transactionService.execute(() -> {
            /*
                保存用户关联角色
             */
            if (!saveList.isEmpty()) {
                userRoleService.batchSave(saveList);
            }
            /*
                更新用户关联角色
             */
            if (!updateList.isEmpty()) {
                userRoleService.batchUpdate(updateList);
            }
        });
    }

    /**
     * 判断部门用户是否满足关联角色条件
     * @param deptRole 部门与角色关联对象
     * @param deptUser 部门与用户关联对象
     * @return true-通过 false-拒绝
     */
    private boolean checkDirectUser(DeptRoleEntity deptRole, DeptUserEntity deptUser) {
        if (CommonEnum.ONE.getValue().equals(deptRole.getUseLeader())) {
            // 非领导专属，直接返回通过
            return true;
        }
        // 判断用户是否部门领导
        return CommonEnum.ZERO.getValue().equals(deptUser.getLeaderStatus());
    }

    /**
     * 判断部门的子、孙部门用户是否满足关联角色条件
     * @param deptRole 部门与角色关联对象
     * @param deptUser 部门与用户关联对象
     * @return true-通过 false-拒绝
     */
    private boolean checkChildrenUser(DeptRoleEntity deptRole, DeptUserEntity deptUser) {
        if (CommonEnum.ZERO.getValue().equals(deptRole.getUseRange())) {
            // 本部门专属，直接返回拒绝
            return false;
        }
        if (CommonEnum.ZERO.getValue().equals(deptRole.getUseLeader())) {
            // 领导专属，判断用户是否部门领导
            return CommonEnum.ZERO.getValue().equals(deptUser.getLeaderStatus());
        }
        return true;
    }

}
